﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Tilver.Common
{
    internal delegate string GetValueHandler(LogEntry entry);
    /// <summary>
    /// 日志输出格式化处理类
    /// </summary>
    internal class AppenderFormatter
    {
        private static readonly Dictionary<string, GetValueHandler> _cache = new Dictionary<string, GetValueHandler>();
        private static readonly Dictionary<Type, Dictionary<string, Func<object,object>>> _messageCache = new Dictionary<Type, Dictionary<string, Func<object,object>>>();
        private static object _syncLock = new object();

        static AppenderFormatter()
        {
            AddCache("Message", (entry) => { return entry.Message.ToString(); });
            AddCache("Newline", (entry) => { return Environment.NewLine; });
            AddCache("TimeStamp", (entry) => { return entry.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss"); });
            AddCache("MachineName", (entry) => { return entry.MachineName; });
            AddCache("MachineIp", (entry) => { return entry.MachineIp; });
            AddCache("AppDomainName", (entry) => { return entry.AppDomainName; });
            AddCache("ProcessId", (entry) => { return entry.ProcessId; });
            AddCache("ProcessName", (entry) => { return entry.ProcessName; });
            AddCache("ManagedThreadName", (entry) => { return entry.ManagedThreadName; });
            AddCache("Win32ThreadId", (entry) => { return entry.Win32ThreadId; });

            AddCache("Exception", (entry) => { return entry.InnerException.ToString(); });
            AddCache("Exception.Message", (entry) => { return entry.InnerException.Message; });
            AddCache("Exception.Source", (entry) => { return entry.InnerException.Source; });
            AddCache("Exception.StackTrace", (entry) => { return entry.InnerException.StackTrace; });
            AddCache("Exception.TargetSite", (entry) => { return entry.InnerException.TargetSite.Name; });

            AddCache("ExData.ExceptionType", (entry) => { return entry.InnerExceptionData.ExceptionType; });
            AddCache("ExData.Message", (entry) => { return entry.InnerExceptionData.Message; });
            AddCache("ExData.AssemblyName", (entry) => { return entry.InnerExceptionData.AssemblyName; });
            AddCache("ExData.ClassName", (entry) => { return entry.InnerExceptionData.ClassName; });
            AddCache("ExData.MethodName", (entry) => { return entry.InnerExceptionData.MethodName; });
            AddCache("ExData.FileName", (entry) => { return entry.InnerExceptionData.FileName; });
            AddCache("ExData.LineNumber", (entry) => { return entry.InnerExceptionData.LineNumber.ToString(); });
            AddCache("ExData.StackTrace", (entry) => { return entry.InnerExceptionData.GetStackTraceString(); });
            AddCache("ExData.UserData", (entry) => { return entry.InnerExceptionData.GetUserDataString(); });
        }
        private static void AddCache(string key, GetValueHandler handler)
        {
            _cache.Add(key.ToLower(), handler);
        }
        /// <summary>
        /// 获取解析后的信息
        /// </summary>
        /// <param name="formatter"></param>
        /// <param name="entry"></param>
        /// <returns></returns>
        public static string GetValue(string formatter, LogEntry entry)
        {
            string ret = string.Empty;
            formatter = formatter.ToLower();
            if (formatter.Contains("message."))
            {
                string propertyName = formatter.Substring(8);
                ret = GetMessageHandler(entry.MessageType, propertyName).Invoke(entry.Message).ToString();
            }
            else
            {
                if (!_cache.ContainsKey(formatter)) { throw new ArgumentException("配置文件中定义的formatter中有错误，LogEntry对象不存在此属性。", "formatter"); }
                ret = _cache[formatter].Invoke(entry);
            }
            return ret;
        }

        private static Func<object,object> GetMessageHandler(Type type, string propertyName)
        {
            if (!_messageCache.ContainsKey(type))
            {
                lock (_syncLock)
                {
                    if (!_messageCache.ContainsKey(type))
                    {
                        var cache = new Dictionary<string, Func<object,object>>();
                        PropertyInfo[] propertys = type.GetProperties();
                        foreach (PropertyInfo p in propertys)
                        {
                            cache.Add(p.Name.ToLower(), DynamicCompiler.CreateGetter(type, p));
                        }
                        _messageCache.Add(type, cache);
                    }
                }
            }
            var handlers = _messageCache[type];
            if (!handlers.ContainsKey(propertyName)) { throw new ArgumentException("配置文件中定义的formatter中有错误，Message对象不存在此属性。", "propertyName"); }
            return handlers[propertyName];
        }
    }
}
